// 使用第三方开源库cpp-httplib，处理用户在网站发起的网络请求，通过处理好的html代码给用户构建网页。
#include <iostream>
#include <signal.h>            //signal():捕捉信号

#include "../common/httplib.h" //引入第三方开源库：httplib.h 来负责网络服务，完成网络请求
#include "oj_control.hpp"      //引入控制器模块
#include "oj_control4.hpp"      //引入控制器模块(竞赛版)

using namespace httplib;    // 展开httplib库
using namespace ns_control; // 展开控制器模块
using namespace ns_control4; // 展开控制器模块

/*捕捉信号函数用来启动服务器*/
static Control *ctrl_ptr = nullptr;
void Recovery(int signo)
{
    ctrl_ptr->RecoveryMachine(); //启动主机列表中所有负责编译运行服务的主机
}

int main()
{
    signal(SIGQUIT, Recovery); // 捕捉SIGQUIT信号(Ctrl+\)

    Server svr; // 创建一个客户端对象来接收并处理请求

    Control ctrl;   //面试题
    Control4 ctrl4; //竞赛题
    ctrl_ptr = &ctrl;

    /**************************************************************************************
     * 1.用户发起/all_questions请求，申请获取所有的题目列表，使用lambda函数处理用户发起的请求。
     * lambda函数里的两个参数：
     *     const Request &req： 请求类,里面保存着用户的请求，即/question/(\d+)
     *     const Request &resq：响应类,对用户请求做出的响应
     **************************************************************************************/
    svr.Get("/all_questions", [&ctrl](const Request &req, Response &resp)
            {
                // 输出型参数，用来保存渲染好的一张包含有所有题目的网页的html代码
                std::string html;
                // control模块调用model模块和view模块渲染网页，由输出型参数返回渲染好的网页。
                ctrl.AllQuestions(&html);
                // 给用户返回渲染好的网页（会直接将网页显示在 公网IP:port/all_questions上）
                resp.set_content(html, "text/html; charset=utf-8"); 
            });

    /**************************************************************************************
     * 1.2 用户发起/all_questions4请求，申请获取所有的竞赛题目列表，使用lambda函数处理用户发起的请求。
     * lambda函数里的两个参数：
     *     const Request &req： 请求类,里面保存着用户的请求，即/question/(\d+)
     *     const Request &resq：响应类,对用户请求做出的响应
     **************************************************************************************/
    svr.Get("/all_questions4", [&ctrl4](const Request &req, Response &resp)
            {
                // 输出型参数，用来保存渲染好的一张包含有所有题目的网页的html代码
                std::string html;
                // control模块调用model模块和view模块渲染网页，由输出型参数返回渲染好的网页。
                ctrl4.AllQuestions4(&html);
                // 给用户返回渲染好的网页（会直接将网页显示在 公网IP:port/all_questions上）
                resp.set_content(html, "text/html; charset=utf-8"); 
            });

    /*****************************************************************************************************
     * 2.1 用户发起请求/question/(\d+)，申请获取单个题目的内容
     * 参数一：R"(/question/(\d+))"
     *     question/(\d+) : (\d+)正则匹配任意长度的数字(cpp-httplib中引入了<regex>支持了正则表达式)
     *     R"()", 原始字符串raw string,保持字符串内容的原貌，不做相关的转义(\d是转义字符，故要使用R"()")
     * 参数二：[&ctrl](const Request &req, Response &resp){}
     *     const Request &req： 请求类,里面保存着用户的请求(matches)，即/question/(\d+)和网页发来的数据(body)
     *     const Request &resq：响应类,对用户请求做出的响应
     ****************************************************************************************************/
    svr.Get(R"(/question/(\d+))", [&ctrl](const Request &req, Response &resp)
            {
                std::string number = req.matches[1];// 通过请求类，获取请求的第二部分内容: (\d+)
                std::string html ;
                // control模块调用model模块和view模块渲染网页
                ctrl.Question(number, &html);
                // 给用户返回渲染好的网页
                resp.set_content(html, "text/html; charset=utf-8"); 
            });
    /*****************************************************************************************************
     * 2.2 用户发起请求/question4/(\d+)，申请获取竞赛列表中单个题目的内容
     * 参数一：R"(/question/(\d+))"
     *     question/(\d+) : (\d+)正则匹配任意长度的数字(cpp-httplib中引入了<regex>支持了正则表达式)
     *     R"()", 原始字符串raw string,保持字符串内容的原貌，不做相关的转义(\d是转义字符，故要使用R"()")
     * 参数二：[&ctrl](const Request &req, Response &resp){}
     *     const Request &req： 请求类,里面保存着用户的请求(matches)，即/question/(\d+)和网页发来的数据(body)
     *     const Request &resq：响应类,对用户请求做出的响应
     ****************************************************************************************************/
    svr.Get(R"(/question4/(\d+))", [&ctrl4](const Request &req, Response &resp)
        {
            std::string number = req.matches[1];// 通过请求类，获取请求的第二部分内容: (\d+)
            std::string html ;
            // control模块调用model模块和view模块渲染网页
            ctrl4.Question4(number, &html);
            // 给用户返回渲染好的网页
            resp.set_content(html, "text/html; charset=utf-8"); 
        });

    /* 3.1 用户点击提交代码发起请求 /judge/(\d+)，申请判题*/
    svr.Post(R"(/judge/(\d+))", [&ctrl](const Request &req, Response &resp)
             {
                 std::string number = req.matches[1]; // 通过请求类，获取请求的第二部分内容: (\d+)
                 std::string result_json;
                 ctrl.Judge(number, req.body, &result_json); // 把网页传来Json串(req.body)给control模块下的判题模块，通过判题模块把Json串给负责编译运行服务的主机。
                 //以把包含判题结果的Json串以Json形式返回给用户
                 resp.set_content(result_json, "application/json;charset=utf-8");
             });
    /* 3.2 用户点击提交代码发起请求 /judge4/(\d+)，申请判题*/
    svr.Post(R"(/judge4/(\d+))", [&ctrl4](const Request &req, Response &resp)
             {
                 std::string number = req.matches[1]; // 通过请求类，获取请求的第二部分内容: (\d+)
                 std::string result_json;
                 ctrl4.Judge4(number, req.body, &result_json); // 把网页传来Json串(req.body)给control模块下的判题模块，通过判题模块把Json串给负责编译运行服务的主机。
                 //以把包含判题结果的Json串以Json形式返回给用户
                 resp.set_content(result_json, "application/json;charset=utf-8");
             });
    // 拓展：
    // 1.用户发起登录请求
    // 2.用户发起求职请求
    // 3.用户发起讨论请求

    svr.set_base_dir("./wwwroot"); // 设置网站首页
    svr.listen("0.0.0.0", 8080);
    return 0;
}